home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume10 / comobj.lisp / part07 < prev    next >
Encoding:
Text File  |  1987-08-01  |  50.4 KB  |  1,586 lines

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v10i081:  Common Ojbects, Common Loops, Common Lisp, Part07/13
  5. Message-ID: <750@uunet.UU.NET>
  6. Date: 3 Aug 87 03:01:21 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 1575
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: Roy D'Souza <dsouza%hplabsc@hplabs.HP.COM>
  12. Posting-number: Volume 10, Issue 81
  13. Archive-name: comobj.lisp/Part07
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 7 (of 13)."
  22. # Contents:  co-dmeth.l macros.l
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'co-dmeth.l' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'co-dmeth.l'\"
  26. else
  27. echo shar: Extracting \"'co-dmeth.l'\" \(22335 characters\)
  28. sed "s/^X//" >'co-dmeth.l' <<'END_OF_FILE'
  29. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  30. X;
  31. X; File:         co-dmeth.l
  32. X; RCS:          $Revision: 1.1 $
  33. X; SCCS:         %A% %G% %U%
  34. X; Description:  Defining CommonObjects methods
  35. X; Author:       James Kempf
  36. X; Created:      March 10, 1987
  37. X; Modified:     12-Mar-87 09:21:38 (James Kempf)
  38. X; Language:     Lisp
  39. X; Package:      COMMON-OBJECTS
  40. X; Status:       Distribution
  41. X;
  42. X; (c) Copyright 1987, HP Labs, all rights reserved.
  43. X;
  44. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  45. X;
  46. X; Copyright (c) 1987 Hewlett-Packard Corporation. All rights reserved.
  47. X;
  48. X; Use and copying of this software and preparation of derivative works based
  49. X; upon this software are permitted.  Any distribution of this software or
  50. X; derivative works must comply with all applicable United States export
  51. X; control laws.
  52. X; 
  53. X; This software is made available AS IS, and Hewlett-Packard Corporation makes
  54. X; no warranty about the software, its performance or its conformity to any
  55. X; specification.
  56. X;
  57. X; Suggestions, comments and requests for improvement may be mailed to
  58. X; aiws@hplabs.HP.COM
  59. X
  60. X;;;-*-Mode:LISP; Package:(CO (PCL LISP)); Base:10; Syntax: Common-lisp-*-
  61. X;;;
  62. X;;; *************************************************************************
  63. X;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
  64. X;;;
  65. X;;; Use and copying of this software and preparation of derivative works
  66. X;;; based upon this software are permitted.  Any distribution of this
  67. X;;; software or derivative works must comply with all applicable United
  68. X;;; States export control laws.
  69. X;;; 
  70. X;;; This software is made available AS IS, and Xerox Corporation makes no
  71. X;;; warranty about the software, its performance or its conformity to any
  72. X;;; specification.
  73. X;;; 
  74. X;;; Any person obtaining a copy of this software is requested to send their
  75. X;;; name and post office or electronic mail address to:
  76. X;;;   CommonLoops Coordinator
  77. X;;;   Xerox Artifical Intelligence Systems
  78. X;;;   2400 Hanover St.
  79. X;;;   Palo Alto, CA 94303
  80. X;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
  81. X;;;
  82. X;;; Suggestions, comments and requests for improvements are also welcome.
  83. X;;; *************************************************************************
  84. X
  85. X(in-package 'common-objects :nicknames '(co) :use '(lisp pcl walker))
  86. X
  87. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  88. X; 
  89. X;  nued) Support for Using Keywords as Method Names
  90. X;
  91. X;  These macros and functions translate keyword method names into
  92. X;  names in a package. Some Common Lisps do allow keyword symbols
  93. X;  to have an associated function, others don't. Rather than
  94. X;  differentiating, a single package, KEYWORD-STANDIN, is used
  95. X;  for method symbols which are keywords.
  96. X;
  97. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  98. X
  99. X(defun keyword-standin (keyword)
  100. X
  101. X  ;;An example of a special method is :print which gets
  102. X  ;;  translated into the symbol pcl:print-instance
  103. X
  104. X  (if (special-keyword-p keyword)
  105. X    (keyword-standin-special keyword)
  106. X    (intern (symbol-name keyword) *keyword-standin-package*)
  107. X  )
  108. X
  109. X) ;end keyword-standin
  110. X
  111. X;;unkeyword-standin-Return the keyword for a standin symbol
  112. X
  113. X(defun unkeyword-standin (symbol)
  114. X  
  115. X  (if (special-method-p symbol)
  116. X    (unkeyword-standin-special symbol)
  117. X      (if (eq (symbol-package symbol) *keyword-standin-package*)
  118. X    (setf symbol (intern (symbol-name symbol) (find-package :keyword)))
  119. X    symbol
  120. X
  121. X       ) ;if
  122. X
  123. X  ) ;if
  124. X
  125. X) ;end unkeyword-standin
  126. X
  127. X;;Set up the universal method selector list, for fast messaging
  128. X
  129. X(eval-when (load eval)
  130. X  (dolist (l *universal-methods*)
  131. X    (push (keyword-standin l) *universal-method-selectors*)
  132. X  )
  133. X)
  134. X
  135. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  136. X; 
  137. X;    Runtime Interface to the Slots
  138. X;
  139. X;  The extra slots are used for the pointer to self and for parents. Each 
  140. X;  ancestor is actually a fully fledged object of the ancestor type, except its 
  141. X;  pointer to self slot points back to the original object piece.
  142. X;  Slot indicies can be calculated directly at compile time, since they do
  143. X;  not change after the object is created.
  144. X;
  145. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  146. X
  147. X;;self-from-inner-self-Return the pointer to the original object
  148. X
  149. X(defmacro self-from-inner-self ()
  150. X  `(%instance-ref .inner-self. ,$SELF-INDEX)
  151. X
  152. X) ;end self-from-inner-self
  153. X
  154. X;;parent-from-inner-self-Given the parent's name, return a pointer
  155. X;;  to the object piece in which the instance variables are stored.
  156. X
  157. X(defmacro parent-from-inner-self (parent-class-name)
  158. X  `(get-slot .inner-self. ',(local-super-slot-name parent-class-name))
  159. X
  160. X) ;end parent-from-inner-self
  161. X
  162. X;;local-super-slot-name-Generate a slot name for the parent's instance
  163. X;;  variable
  164. X
  165. X(defun local-super-slot-name (local-super-name)
  166. X  (intern (concatenate 'string
  167. X        "Slot For "
  168. X            (symbol-name local-super-name)))
  169. X
  170. X) ;end local-super-slot-name
  171. X
  172. X;;calculate-slot-index-Return the index of the slot in the vector
  173. X
  174. X(defun calculate-slot-index (slotname parents slots)
  175. X
  176. X  (let
  177. X    (
  178. X      (parloc (position slotname parents))
  179. X      (sloc  (position slotname slots))
  180. X    )
  181. X
  182. X    (if parloc
  183. X     (+ $START-OF-PARENTS parloc)
  184. X     (+ $START-OF-PARENTS (length parents) sloc)
  185. X    )
  186. X
  187. X  )
  188. X
  189. X)
  190. X
  191. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  192. X; 
  193. X;    New Method Class For CommonObjects
  194. X;
  195. X;  CommonObjects methods need to keep track of their method symbol, so
  196. X;  that the symbol can be looked up and inserted into a CALL-METHOD
  197. X;  or APPLY-METHOD when a method including one of these forms is loaded.
  198. X;  The new method keeps track of a method symbol as an instance variable,
  199. X;  and maintains the symbol's function cell with an accurate pointer to
  200. X;  the current function implementing the method. The function is called
  201. X;  through this symbol during run-time processing of a CALL-METHOD.
  202. X;  Note that, since the method object gets created when the method
  203. X;  is loaded (or, alternatively, looked up, if a CALL-METHOD was
  204. X;  processed before the method was defined), the symbol will be GENSYM'ed
  205. X;  in the load time environment. Fully qualified symbols are needed for
  206. X;  the method names because they are not exported from the PCL package.
  207. X;
  208. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  209. X
  210. X;;common-objects-method-Add an additional slot for the function symbol name
  211. X
  212. X(ndefstruct 
  213. X  (common-objects-method (:class class) 
  214. X    (:include pcl::method)
  215. X    (:conc-name method-)
  216. X  )
  217. X    (function-symbol NIL)    ;;name of the method function
  218. X                ;;  used for call-method
  219. X
  220. X) ;end common-objects-method
  221. X
  222. X;;method-function-Need this to have the SETF
  223. X;;  method work correctly
  224. X
  225. X(defmeth method-function  ((method common-objects-method))
  226. X
  227. X  ;;This was RUN-SUPER-INTERNAL, but now changed to accomodate
  228. X  ;;  new code.
  229. X
  230. X  (call-next-method)
  231. X
  232. X
  233. X) ;end method-function
  234. X
  235. X;;method-function-Even though we may not yet be able to
  236. X;;  determine what the function symbol is, the SETF method
  237. X;;  must reset the symbol's function, in the event the
  238. X;;  method object is recycled. 
  239. X
  240. X(defmeth (method-function (:setf (nv))) ((method common-objects-method))
  241. X
  242. X
  243. X    ;;If the method function symbol for the CALL-METHOD optimization
  244. X    ;;  has not yet been set, do it.
  245. X
  246. X    (when (method-function-symbol method)
  247. X      (setf (symbol-function (method-function-symbol method)) 
  248. X        nv
  249. X      )
  250. X
  251. X    )
  252. X
  253. X
  254. X    ;;This was RUN-SUPER-INTERNAL, but now changed to accomodate
  255. X    ;; new code.
  256. X
  257. X    (call-next-method)
  258. X
  259. X) ;end method-function :setf
  260. X
  261. X;;method-discriminator-Need this to have the SETF
  262. X;;  method work correctly
  263. X
  264. X(defmeth method-discriminator  ((method common-objects-method))
  265. X
  266. X  ;;This was RUN-SUPER-INTERNAL, but now changed to accomodate
  267. X  ;;  new code.
  268. X
  269. X  (call-next-method)
  270. X
  271. X
  272. X) ;end method-discriminator
  273. X
  274. X;;method-discriminator-By the time the method's discriminator is
  275. X;;  set, the method has enough information to generate the
  276. X;;  symbol for CALL-METHOD optimization.
  277. X
  278. X(defmeth (method-discriminator (:setf (nv))) ((method common-objects-method))
  279. X
  280. X
  281. X    ;;If the method function symbol for the CALL-METHOD optimization
  282. X    ;;  has not yet been set, do it.
  283. X
  284. X    (when (not (method-function-symbol method))
  285. X      (setf (method-function-symbol method) 
  286. X            (generate-method-function-symbol
  287. X          (class-name (car (method-type-specifiers method)))
  288. X          (discriminator-name nv)
  289. X        )
  290. X      )
  291. X      (setf (symbol-function (method-function-symbol method)) 
  292. X        (method-function method)
  293. X      )
  294. X
  295. X    )
  296. X
  297. X
  298. X    ;;This was RUN-SUPER-INTERNAL, but now changed to accomodate
  299. X    ;; new code.
  300. X
  301. X    (call-next-method)
  302. X
  303. X) ;end method-discriminator :setf
  304. X
  305. X;;generate-method-function-symbol-Generate a method function
  306. X;;  symbol for the method. Used in the CALL-METHOD optimization.
  307. X
  308. X(defun generate-method-function-symbol (class-name message)
  309. X
  310. X  ;;Generate a symbol for the function to be called.
  311. X  ;;  This is in the same package as the method name
  312. X  ;;  symbol, and its name as the form:
  313. X  ;;  <class package name>;;<class name> <message package name>;;<message>
  314. X  ;;  Note that this will avoid collisions for two methods with
  315. X  ;;  the same name and different packages, because the symbol
  316. X  ;;  names (as well as the packages) are different.
  317. X  ;;  We hope that this should avoid collision.
  318. X
  319. X  (intern
  320. X    (concatenate 'simple-string 
  321. X         (package-name (symbol-package class-name))
  322. X         ";;"
  323. X         (symbol-name class-name)
  324. X         " " 
  325. X         (package-name     
  326. X           (if (keywordp message)
  327. X                     (find-package 'keyword-standin)
  328. X                     (symbol-package message)
  329. X                   )
  330. X                 )
  331. X         ";;"
  332. X         (symbol-name message)
  333. X    )
  334. X    (if (keywordp message)
  335. X      (find-package 'keyword-standin)
  336. X      (symbol-package message)
  337. X    )
  338. X ) 
  339. X
  340. X) ;generate-method-function-symbol
  341. X
  342. X;;expand-with-make-entries-Returns an alist of the form:
  343. X;; 
  344. X;;   (<prefix+slot-name> <instance-form> <class> <slotd> <use-slot-value-p>)
  345. X;;
  346. X
  347. X(defmeth expand-with-make-entries ((method common-objects-method) first-arg)
  348. X         (declare (ignore first-arg))   ; rds 3/8
  349. X  (let* 
  350. X    (
  351. X      (entries ())
  352. X      (method-argument (first (method-arglist method)))
  353. X      (method-type-spec (first (method-type-specifiers method)))
  354. X    )          
  355. X
  356. X    ;;CommonObjects methods only discriminate on the first 
  357. X    ;;  argument. Also, we always want to use the slot value,
  358. X    ;;  since there is no slotd-accessor.
  359. X
  360. X    (dolist (slotd (class-slots method-type-spec))
  361. X      (push
  362. X        (list
  363. X          (slotd-name slotd)    ;;the slot name
  364. X          method-argument    ;;the instance arg name
  365. X          method-type-spec    ;;the class
  366. X          slotd            ;;the slot descriptor
  367. X          T                  ;;use the slot value directly
  368. X        )
  369. X        entries
  370. X      )
  371. X    ) ;dolist
  372. X
  373. X    entries
  374. X
  375. X  ) ;let*
  376. X
  377. X) ;expand-with-make-entries
  378. X
  379. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  380. X;              Messaging Macros and Functions
  381. X;
  382. X;   Message sending becomes funcalling the message.
  383. X;   We convert all message sends to a funcall of the message.  Because
  384. X;   CommonObjects encourages messages to be keywords and keywords are
  385. X;   not funcallable, we have to have a special package in which keywords
  386. X;   are interned before their use as messages.
  387. X;
  388. X;   As an example of all this, take the expansion of a sample =>:
  389. X;
  390. X;      (=> object :message arg-1 arg-2)  expands into:
  391. X;
  392. X;      (funcall 'keyword-standin::message object arg-1 arg-2)
  393. X;
  394. X;   This means that all CommonObjects discriminators will be classical.
  395. X;   That is they will discriminator only on the class of their first
  396. X;   argument.
  397. X; 
  398. X;   The first argument to any method will always be the inner self, that is
  399. X;   an instance of the same class as the method was defined on.  This is
  400. X;   bound to the symbol .INNER-SELF., special macros SELF-FROM-INNER-SELF
  401. X;   and PARENT-FROM-INNER-SELF are used to access outer-self and parent
  402. X;   instances.
  403. X;
  404. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  405. X
  406. X;;make-set-message-Construct a :SET-xxx message for SETF
  407. X
  408. X(defmacro make-set-message (message)
  409. X  
  410. X  `(intern
  411. X    (concatenate 'simple-string 
  412. X                 "SET-" 
  413. X                 (symbol-name ,message)
  414. X    )
  415. X    (symbol-package ,message)
  416. X
  417. X  )
  418. X
  419. X) ;make-set-message
  420. X
  421. X;;=>-Convert to PCL messaging. Note that no error or type checking occurs.
  422. X
  423. X(defmacro => (object message &rest args)
  424. X
  425. X  `(funcall
  426. X      ,(if (keywordp message)
  427. X    `',(keyword-standin message)
  428. X        message
  429. X      )
  430. X      ,object 
  431. X      ,@args
  432. X  )
  433. X
  434. X) ;end =>
  435. X
  436. X;;send?-Messaging macro which returns NIL if something is wrong.
  437. X
  438. X(defmacro send? (object message &rest args)
  439. X
  440. X  `(send?-internal 
  441. X    ,object 
  442. X    ,(if (keywordp message)
  443. X    `',(keyword-standin message)
  444. X     message
  445. X    )  
  446. X    ,@args
  447. X  )
  448. X
  449. X) ;end send?
  450. X
  451. X;;Setf definitions for messaging macros.
  452. X
  453. X(defsetf => (obj message) (new-value)
  454. X
  455. X  `(progn
  456. X      (=> ,obj 
  457. X          ,(if (keywordp message)
  458. X            (make-set-message message)
  459. X            `(make-set-message ,message)
  460. X          )
  461. X      ,new-value
  462. X      )
  463. X    )
  464. X) ;end defsetf for =>
  465. X
  466. X(defsetf send? (obj message) (new-value)
  467. X  `(progn
  468. X      (send? ,obj 
  469. X             ,(if (keywordp message)
  470. X               (make-set-message message)
  471. X               `(make-set-message ,message)
  472. X              )
  473. X        ,new-value
  474. X      )
  475. X    )
  476. X) ;end defsetf for send?
  477. X
  478. X;;send?-internal-Process the message invocation into correct code for
  479. X;; SEND?
  480. X
  481. X(defun send?-internal (object message &rest args)
  482. X
  483. X  (if object
  484. X    (let*
  485. X       (
  486. X         (class (class-of object))
  487. X         (class-name (class-name class))
  488. X         (metaclass-name (class-name (class-of class)))
  489. X
  490. X       )
  491. X
  492. X      ;;Check if OBJECT is an instance and class is still defined
  493. X      ;;  and operation is supported.
  494. X
  495. X      (if (and
  496. X           (eq metaclass-name 'common-objects-class)
  497. X           (not (eq class-name $UNDEFINED-TYPE-NAME))
  498. X           (fast-supports-operation-p class message)
  499. X          )
  500. X
  501. X          (apply message  object args)
  502. X
  503. X          NIL
  504. X
  505. X      ) ;if
  506. X
  507. X    ) ;let*
  508. X
  509. X  ) ;if
  510. X
  511. X) ;send?-internal
  512. X
  513. X;;fast-supports-operation-p-Does no checking on CLASS
  514. X
  515. X(defun fast-supports-operation-p (class message)
  516. X
  517. X;;Check first if its a universal method
  518. X
  519. X  (if (member (unkeyword-standin message) *universal-methods*)
  520. X
  521. X    T
  522. X
  523. X    ;;Otherwise, check in the class object if it's got them
  524. X
  525. X    (dolist (methobj (pcl::class-direct-methods class))
  526. X
  527. X      (when (eq (method-name methobj) message)
  528. X        (return-from fast-supports-operation-p T)
  529. X      )
  530. X
  531. X    ) ;dolist
  532. X  ) ;if
  533. X
  534. X) ;fast-supports-operation-p
  535. X
  536. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  537. X;  Method Definition
  538. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  539. X
  540. X;;defcommon-objects-meth-Create method and discriminator objects and
  541. X;;  call EXPAND-DEFMETH-INTERNAL. The method object is of class
  542. X;;  common-objects-method. Note that this macro gets expanded at the
  543. X;;  time this file is compiled.
  544. X
  545. X(defmacro defcommon-objects-meth (message arglist body)
  546. X
  547. X
  548. X  `(let 
  549. X    (
  550. X      (discriminator-class-object (class-named 'pcl::discriminator t))
  551. X      (method-class-object (class-named 'common-objects-method t))
  552. X    )
  553. X
  554. X    (pcl::expand-defmeth-internal (class-prototype discriminator-class-object)
  555. X                      (class-prototype method-class-object)
  556. X                      (if (listp ,message) ,message (list ,message))
  557. X                      ,arglist
  558. X                      (list ,body)
  559. X    )
  560. X
  561. X  ) ;let
  562. X
  563. X) ;end defcommon-objects-meth
  564. X
  565. X;;define-method-Top level programmer interface to method
  566. X;;  definition
  567. X
  568. X(defmacro define-method (spec arglist &body body)
  569. X
  570. X  ;;Syntax check the call first
  571. X
  572. X  (co-parse-method-macro-call spec arglist body)
  573. X
  574. X  (let* 
  575. X    (
  576. X      (class-name (car spec))
  577. X      (message (if (keywordp (cadr spec))
  578. X             (keyword-standin (cadr spec))
  579. X             (cadr spec)))
  580. X    )
  581. X
  582. X
  583. X    ;;Check first to be sure that class is a CommonObjects class
  584. X
  585. X    (if (not 
  586. X          (eq (class-name (class-of (class-named class-name T))) 'common-objects-class)
  587. X        )
  588. X      (error "DEFINE-METHOD: `~S' is not a CommonObjects type." class-name)
  589. X    )
  590. X
  591. X    ;;The compiler-let of *CURRENT-METHOD-CLASS-NAME* is to support
  592. X    ;;  CALL-METHOD.
  593. X    ;;  Also, bind SELF around the body to outer self.
  594. X    ;;  Note that this allows someone to rebind SELF in the body, but
  595. X    ;;  that rebinding will not affect CALL-METHOD, APPLY-METHOD or IV
  596. X    ;;  access since they don't really use SELF.
  597. X    ;;  Also, use WITH to allow lexical access to the instance 
  598. X    ;;  variables.
  599. X
  600. X    (setq body `(compiler-let 
  601. X                  (
  602. X                    (*current-method-class-name* ',class-name)
  603. X              )
  604. X
  605. X                  (let ((self (self-from-inner-self)))
  606. X            (with* 
  607. X              (
  608. X            (.inner-self. "" ,class-name)
  609. X              )
  610. X
  611. X                      self
  612. X              (progn . ,body))
  613. X                 )
  614. X
  615. X          ) ;compiler-let
  616. X    )      
  617. X
  618. X
  619. X    `(progn
  620. X
  621. X        ,(defcommon-objects-meth message 
  622. X           `((.inner-self. ,class-name) ,@arglist) 
  623. X
  624. X       body
  625. X
  626. X         )
  627. X
  628. X         (list ',class-name ',(cadr spec))
  629. X
  630. X       ) ;progn
  631. X
  632. X   ) ;let*
  633. X
  634. X) ;end define-method
  635. X
  636. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  637. X; 
  638. X;    Call-Method and Optimizations
  639. X;
  640. X;  Because of pf the ambiguous nature of the definition of #, in CLtL,
  641. X;  the implementation of #, may not work correctly on a particular system
  642. X;  when used within the backquote macro in compiled code.
  643. X;  The kind of behavior which is needed is as follows (with reference
  644. X;  to 5.3.3, pg. 70)
  645. X;
  646. X;  1) If the situation is EVAL, then execute the function
  647. X;     LOAD-TIME-GET-CALL-METHOD-FUNCTION-SYMBOL and cache the 
  648. X;     method symbol in line when the code is macroexpanded.
  649. X;
  650. X;  2) If the situation is compile, then arrange for the function
  651. X;     LOAD-TIME-GET-CALL-METHOD-FUNCTION-SYMBOL to be executed
  652. X;     and the result cached only when the file gets loaded.
  653. X;
  654. X;  What I want to say is:
  655. X;
  656. X;   `(,caller
  657. X;         #,(load-time-get-call-method-function ',class-name ',method-name
  658. X;                           ',arglist
  659. X;          )
  660. X;          <rest of form>
  661. X;     )
  662. X;
  663. X;  and have it work correctly. Well, it doesn't always.
  664. X;
  665. X;  Alternatively, I would like to generate a closure at compile time
  666. X;  which will get fasled into the output file and will cache the
  667. X;  method symbol the first time it is called. But that doesn't
  668. X;  always work either.
  669. X;
  670. X;  So, instead, I tried using an elaborate scheme which creates vectors
  671. X;  at compile time and uses a top level (EVAL-WHEN (LOAD) ...) to 
  672. X;  depost the method symbol at load time. The special variable
  673. X;  *LIST-OF-CALL-METHOD-FIXUPS* gets bound to NIL before every
  674. X;  DEFINE-METHOD invocation. The CALL-METHOD macro creates
  675. X;  instances of the DEFSTRUCT CALL-METHOD-RECORD and pushes them
  676. X;  on *LIST-OF-CALL-METHOD-FIXUPS* recording CALL-METHODs and
  677. X;  vectors for caching the method symbol. The CALL-METHOD macro
  678. X;  can do this because the PCL method EXPAND-DEFMETH-INTERNAL
  679. X;  is replaced in the patches file. This new method walks
  680. X;  them method code body during the execution of EXPAND-DEFMETH-INTERNAL
  681. X;  rather than at the top level, as in the stock PCL system.
  682. X;  If this change is NOT made, then the method body must
  683. X;  be prewalked before code generation, because the code
  684. X;  walk (during which CALL-METHOD gets expanded) doesn't
  685. X;  occur until after DEFINE-METHOD returns to the top level.
  686. X;
  687. X;  As the last part of the DEFINE-METHOD code generation,
  688. X;  a top level (EVAL-WHEN (LOAD EVAL) ...) is generated to get
  689. X;  the method symbol at load time and deposit it in the
  690. X;  vector. The SVREF gets the symbol at the time the CALL-METHOD
  691. X;  is invoked. So, in effect, I'm generating my own
  692. X;  closure.
  693. X;
  694. X;  Well, that doesn't work either. Why? Because once the
  695. X;  vector is deposited into the code, there is no guarantee
  696. X;  that it will be EQ to the one in the list. And, in any
  697. X;  event, this scheme won't work in traditional interpreters
  698. X;  which expand macros as they are encountered, since the
  699. X;  top level (EVAL-WHEN (LOAD EVAL) ... ) gets done before
  700. X;  the CALL-METHOD macro is fully expanded.
  701. X;
  702. X;  Sigh. The only choice is to GENSYM a symbol at compile
  703. X;  time and pray that it doesn't trash something at load time.
  704. X;  But maybe that's OK.
  705. X;
  706. X;  Note that the general behavior which is desired here is loadtime 
  707. X;  execution within generated code, rather than at the top level.
  708. X;
  709. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  710. X
  711. X;;call-method-Top level macro for CALL-METHOD.
  712. X
  713. X(defmacro call-method (spec &rest args)
  714. X  (call-method-internal 'call-method spec args) 
  715. X
  716. X) ;end call-method
  717. X
  718. X;;apply-method-Top level macro for APPLY-METHOD.
  719. X
  720. X(defmacro apply-method (spec &rest args)
  721. X  (call-method-internal 'apply-method spec args)
  722. X
  723. X) ;end apply-method
  724. X
  725. X;;call-method-internal-Process a CALL-METHOD invocation.
  726. X
  727. X(defun call-method-internal (for spec args)
  728. X  (declare (special *current-method-class-name*))
  729. X  (if (null (boundp '*current-method-class-name*))
  730. X      (error "Attempt to use ~S other than inside a method.~%" for)
  731. X      (let* ((caller (ecase for
  732. X              (call-method 'funcall)
  733. X              (apply-method 'apply)))
  734. X        (class-name (if (listp spec)
  735. X                (car spec)
  736. X                *current-method-class-name*))
  737. X        (message (if (listp spec) (cadr spec) spec))
  738. X
  739. X        (fsym (generate-method-function-symbol class-name message))
  740. X
  741. X          )
  742. X
  743. X
  744. X         ;;Check the syntax
  745. X
  746. X         (co-parse-call-to-method (list for spec args) 
  747. X                                  (symbol-name for)
  748. X                                  *current-method-class-name*
  749. X         )
  750. X
  751. X
  752. X         ;;Generate code. Note there is no need to check
  753. X         ;;  whether or not the method function symbol
  754. X         ;;  is bound or to do any fixing up at all.
  755. X         ;;  If it is not, then its an error, because
  756. X         ;;  the method hasn't yet been defined. The
  757. X         ;;  function cell will be bound when the 
  758. X         ;;  method gets defined.
  759. X
  760. X    `(,caller (symbol-function ',fsym)
  761. X
  762. X      ,(if (listp spec)
  763. X           `(parent-from-inner-self ,class-name)
  764. X           '.inner-self.)
  765. X      ,@args)
  766. X    ) ;let
  767. X  ) ;if
  768. X
  769. X) ;end call-method-internal
  770. X
  771. X
  772. X;;legal-parent-p-Is parent-name a legal parent of class-name?
  773. X
  774. X(defun legal-parent-p (class-name parent-name)
  775. X
  776. X  (member parent-name 
  777. X          (class-local-super-names (class-named class-name T))
  778. X          :test #'eq
  779. X
  780. X  )
  781. X) ;legal-parent-p
  782. X
  783. X
  784. END_OF_FILE
  785. if test 22335 -ne `wc -c <'co-dmeth.l'`; then
  786.     echo shar: \"'co-dmeth.l'\" unpacked with wrong size!
  787. fi
  788. # end of 'co-dmeth.l'
  789. fi
  790. if test -f 'macros.l' -a "${1}" != "-c" ; then 
  791.   echo shar: Will not clobber existing file \"'macros.l'\"
  792. else
  793. echo shar: Extracting \"'macros.l'\" \(25561 characters\)
  794. sed "s/^X//" >'macros.l' <<'END_OF_FILE'
  795. X;;;-*-Mode:LISP; Package:(PCL (LISP WALKER)); Base:10; Syntax:Common-lisp -*-
  796. X;;;
  797. X;;; *************************************************************************
  798. X;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
  799. X;;;
  800. X;;; Use and copying of this software and preparation of derivative works
  801. X;;; based upon this software are permitted.  Any distribution of this
  802. X;;; software or derivative works must comply with all applicable United
  803. X;;; States export control laws.
  804. X;;; 
  805. X;;; This software is made available AS IS, and Xerox Corporation makes no
  806. X;;; warranty about the software, its performance or its conformity to any
  807. X;;; specification.
  808. X;;; 
  809. X;;; Any person obtaining a copy of this software is requested to send their
  810. X;;; name and post office or electronic mail address to:
  811. X;;;   CommonLoops Coordinator
  812. X;;;   Xerox Artifical Intelligence Systems
  813. X;;;   2400 Hanover St.
  814. X;;;   Palo Alto, CA 94303
  815. X;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
  816. X;;;
  817. X;;; Suggestions, comments and requests for improvements are also welcome.
  818. X;;; *************************************************************************
  819. X;;;
  820. X;;; Macros global variable definitions, and other random support stuff used
  821. X;;; by the rest of the system.
  822. X;;;
  823. X;;; For simplicity (not having to use eval-when a lot), this file must be
  824. X;;; loaded before it can be compiled.
  825. X;;;
  826. X
  827. X(in-package 'pcl :nicknames '(portable-commonloops) :use '(lisp walker))
  828. X
  829. X(export '(defclass
  830. X      defmethod
  831. X      print-object
  832. X
  833. X      print-instance
  834. X      ndefstruct
  835. X      defmeth
  836. X      run-super
  837. X      make
  838. X      initialize
  839. X      get-slot
  840. X      with
  841. X      with*
  842. X      class-of
  843. X      class-named
  844. X      discriminator-named
  845. X      class-prototype
  846. X      class
  847. X      object
  848. X
  849. X
  850. X
  851. X      essential-class
  852. X      
  853. X      class-name
  854. X      class-precedence-list
  855. X      class-local-supers
  856. X      class-local-slots
  857. X      class-direct-subclasses
  858. X      class-direct-methods
  859. X      class-slots
  860. X
  861. X
  862. X      essential-discriminator
  863. X
  864. X      discriminator-name
  865. X      discriminator-methods
  866. X      discriminator-discriminating-function
  867. X
  868. X      essential-method
  869. X
  870. X      method-discriminator
  871. X      method-arglist
  872. X      method-argument-specifiers            
  873. X      method-function
  874. X
  875. X      method-equal
  876. X
  877. X      discriminator-methods
  878. X
  879. X      slotd-name
  880. X      slot-missing
  881. X
  882. X      define-meta-class
  883. X      %make-instance
  884. X      %instance-ref
  885. X      %instancep
  886. X      %instance-meta-class
  887. X
  888. X      make-instance
  889. X      get-slot
  890. X      put-slot
  891. X      get-slot-using-class
  892. X      optimize-slot-access
  893. X      define-class-of-clause
  894. X      add-named-class
  895. X      class-for-redefinition
  896. X      add-class
  897. X      supers-changed
  898. X      slots-changed
  899. X      check-super-meta-class-compatibility
  900. X      check-meta-class-change-compatibility
  901. X      make-slotd
  902. X      compute-class-precedence-list
  903. X      walk-method-body
  904. X      walk-method-body-form
  905. X      optimize-get-slot
  906. X      optimize-set-of-get-slot
  907. X      variable-lexical-p
  908. X      add-named-method
  909. X      add-method
  910. X      remove-named-method
  911. X      remove-method
  912. X      find-method
  913. X      find-method-internal
  914. X      make-discriminating-function
  915. X      install-discriminating-function
  916. X      no-matching-method
  917. X      class-class-precedence-list
  918. X      class-local-supers
  919. X      class-direct-subclasses
  920. X      class-name
  921. X      
  922. X      )
  923. X    (find-package 'pcl))
  924. X
  925. X(proclaim '(declaration values            ;I use this so that Zwei can
  926. X                        ;remind me what values a
  927. X                        ;function returns.
  928. X            
  929. X            method-function-name    ;This is used so that some
  930. X                        ;systems can print the name
  931. X                        ;of the method when I am in
  932. X                        ;the debugger.
  933. X                        ))
  934. X
  935. X;;; Age old functions which CommonLisp cleaned-up away.  They probably exist
  936. X;;; in other packages in all CommonLisp implementations, but I will leave it
  937. X;;; to the compiler to optimize into calls to them.
  938. X;;;
  939. X;;; Common Lisp BUG:
  940. X;;;    Some Common Lisps define these in the Lisp package which causes
  941. X;;;    all sorts of lossage.  Common Lisp should explictly specify which
  942. X;;;    symbols appear in the Lisp package.
  943. X;;;    
  944. X(defmacro memq (item list) `(member ,item ,list :test #'eq))
  945. X(defmacro assq (item list) `(assoc ,item ,list :test #'eq))
  946. X(defmacro rassq (item list) `(rassoc ,item ,list :test #'eq))
  947. X(defmacro delq (item list) `(delete ,item ,list :test #'eq))
  948. X(defmacro neq (x y) `(not (eq ,x ,y)))
  949. X
  950. X(defun make-caxr (n form)
  951. X  (if (< n 4)
  952. X      `(,(nth n '(car cadr caddr cadddr)) ,form)
  953. X      (make-caxr (- n 4) `(cddddr ,form))))
  954. X
  955. X(defun make-cdxr (n form)
  956. X  (cond ((zerop n) form)
  957. X    ((< n 5) `(,(nth n '(identity cdr cddr cdddr cddddr)) ,form))
  958. X    (t (make-cdxr (- n 4) `(cddddr ,form)))))
  959. X
  960. X(defmacro ignore (&rest vars)
  961. X  #+Symbolics `(progn ,.(remove 'ignore vars))
  962. X  #-Symbolics `(progn ,@vars))
  963. X
  964. X(defun true (&rest ignore) (ignore ignore) t)
  965. X(defun false (&rest ignore) (ignore ignore) nil)
  966. X
  967. X;;; ONCE-ONLY does the same thing as it does in zetalisp.  I should have just
  968. X;;; lifted it from there but I am honest.  Not only that but this one is
  969. X;;; written in Common Lisp.  I feel a lot like bootstrapping, or maybe more
  970. X;;; like rebuilding Rome.
  971. X(defmacro once-only (vars &body body)
  972. X  (let ((gensym-var (gensym))
  973. X        (run-time-vars (gensym))
  974. X        (run-time-vals (gensym))
  975. X        (expand-time-val-forms ()))
  976. X    (dolist (var vars)
  977. X      (push `(if (or (symbolp ,var)
  978. X                     (numberp ,var)
  979. X                     (and (listp ,var)
  980. X              (member (car ,var) '(quote function))))
  981. X                 ,var
  982. X                 (let ((,gensym-var (gensym)))
  983. X                   (push ,gensym-var ,run-time-vars)
  984. X                   (push ,var ,run-time-vals)
  985. X                   ,gensym-var))
  986. X            expand-time-val-forms))    
  987. X    `(let* (,run-time-vars
  988. X            ,run-time-vals
  989. X            (wrapped-body
  990. X              ((lambda ,vars . ,body) . ,(reverse expand-time-val-forms))))
  991. X       `((lambda ,(nreverse ,run-time-vars)  ,wrapped-body)
  992. X         . ,(nreverse ,run-time-vals)))))
  993. X
  994. X(defun extract-declarations (body &optional environment)
  995. X  (declare (values documentation declares body))
  996. X  (let (documentation declares form temp)
  997. X    (when (stringp (car body)) (setq documentation (pop body)))
  998. X    (loop
  999. X      (when (null body) (return))
  1000. X      (setq form (car body))
  1001. X      (cond ((and (listp form) (eq (car form) 'declare))
  1002. X         (push (pop body) declares))
  1003. X;        ((and (neq (setq temp (macroexpand form environment)) form)
  1004. X;          (listp temp)
  1005. X;          (eq (car temp) 'declare))
  1006. X;         (pop body)
  1007. X;         (push temp declares))
  1008. X        (t (return))))
  1009. X    (values documentation declares body)))
  1010. X
  1011. X  ;;   
  1012. X;;;;;; FAST-NCONC Lists
  1013. X  ;;
  1014. X;;; These are based on Interlisp's TCONC function.  They are slighlty
  1015. X;;; generalized to take either the item to nconc onto the end of the list or
  1016. X;;; a cons to add to the end of a list. In addition there is a constructor to
  1017. X;;; make fast-nconc-lists and an accessor to get at a fast-nconc-list's real
  1018. X;;; list.
  1019. X(defmacro make-fast-nconc-list ()
  1020. X  `(let ((fast-nconc-list (cons () (list ()))))
  1021. X     (rplaca fast-nconc-list (cdr fast-nconc-list))
  1022. X     fast-nconc-list))
  1023. X
  1024. X(defmacro fast-nconc-list-real-list (fast-nconc-list)
  1025. X  `(cddr ,fast-nconc-list))
  1026. X
  1027. X(defmacro fast-nconc-cons (fast-nconc-list cons)
  1028. X  (once-only (fast-nconc-list)
  1029. X    `(progn (rplacd (car ,fast-nconc-list) ,cons)
  1030. X            (rplaca ,fast-nconc-list (cdar ,fast-nconc-list)))))
  1031. X
  1032. X(defmacro fast-nconc-item (fast-nconc-list item)
  1033. X  `(fast-nconc-cons ,fast-nconc-list (cons ,item nil)))
  1034. X
  1035. X#+Lucid
  1036. X(eval-when (compile load eval)
  1037. X  (eval `(defstruct ,(intern "FASLESCAPE" (find-package 'lucid)))))
  1038. X
  1039. X; rds 3/8 added -HP and +HP for make-keyword:
  1040. X#-HP
  1041. X(defun make-keyword (symbol)
  1042. X   (intern (symbol-name symbol) '#,(find-package 'keyword)))
  1043. X
  1044. X#+HP
  1045. X(defun make-keyword (symbol)
  1046. X   (intern (symbol-name symbol) (find-package 'keyword)))
  1047. X
  1048. X(defun string-append (&rest strings)
  1049. X  (setq strings (copy-list strings))        ;The explorer can't even
  1050. X                        ;rplaca an &rest arg?
  1051. X  (do ((string-loc strings (cdr string-loc)))
  1052. X      ((null string-loc)
  1053. X       (apply #'concatenate 'string strings))
  1054. X    (rplaca string-loc (string (car string-loc)))))
  1055. X
  1056. X(defun symbol-append (sym1 sym2 &optional (package *package*))
  1057. X  (intern (string-append sym1 sym2) package))
  1058. X
  1059. X(defmacro check-member (place list &key (test #'eql) (pretty-name place))
  1060. X  (once-only (place list)
  1061. X    `(or (member ,place ,list :test ,test)
  1062. X         (error "The value of ~A, ~S is not one of ~S."
  1063. X                ',pretty-name ,place ,list))))
  1064. X
  1065. X
  1066. X
  1067. X;;; A simple version of destructuring-bind.
  1068. X
  1069. X;;; This does no more error checking than CAR and CDR themselves do.  Some
  1070. X;;; attempt is made to be smart about preserving intermediate values.  It
  1071. X;;; could be better, although the only remaining case should be easy for
  1072. X;;; the compiler to spot since it compiles to PUSH POP.
  1073. X;;;
  1074. X;;; Common Lisp BUG:
  1075. X;;;    Common Lisp should have destructuring-bind.
  1076. X;;;    
  1077. X(defmacro destructuring-bind (pattern form &body body)
  1078. X  (multiple-value-bind (ignore declares body)
  1079. X      (extract-declarations body)
  1080. X    (multiple-value-bind (setqs binds)
  1081. X    (destructure pattern form)
  1082. X      `(let ,binds
  1083. X     ,@declares
  1084. X     ,@setqs
  1085. X     . ,body))))
  1086. X
  1087. X(defun destructure (pattern form)
  1088. X  (declare (values setqs binds))
  1089. X  (let ((*destructure-vars* ())
  1090. X    (setqs ()))
  1091. X    (declare (special *destructure-vars*))
  1092. X    (when (not (symbolp form))
  1093. X      (setq *destructure-vars* '(.destructure-form.)
  1094. X        setqs (list `(setq .destructure-form. ,form)))
  1095. X      (setq form '.destructure-form.))
  1096. X    (values (nconc setqs (nreverse (destructure-internal pattern form)))
  1097. X        (delete nil *destructure-vars*))))
  1098. X
  1099. X(defun destructure-internal (pattern form)
  1100. X  ;; When we are called, pattern must be a list.  Form should be a symbol
  1101. X  ;; which we are free to setq containing the value to be destructured.
  1102. X  ;; Optimizations are performed for the last element of pattern cases.
  1103. X  ;; we assume that the compiler is smart about gensyms which are bound
  1104. X  ;; but only for a short period of time.
  1105. X  (declare (special *destructure-vars*))
  1106. X  (let ((gensym (gensym))
  1107. X    (pending-pops 0)
  1108. X    (var nil)
  1109. X    (setqs ()))
  1110. X    (labels
  1111. X        ((make-pop (var form pop-into)
  1112. X       (prog1 
  1113. X         (cond ((zerop pending-pops)
  1114. X            `(progn ,(and var `(setq ,var (car ,form)))
  1115. X                ,(and pop-into `(setq ,pop-into (cdr ,form)))))
  1116. X           ((null pop-into)
  1117. X            (and var `(setq ,var ,(make-caxr pending-pops form))))
  1118. X           (t
  1119. X            `(progn (setq ,pop-into ,(make-cdxr pending-pops form))
  1120. X                ,(and var `(setq ,var (pop ,pop-into))))))
  1121. X         (setq pending-pops 0))))
  1122. X      (do ((pat pattern (cdr pat)))
  1123. X      ((null pat) ())
  1124. X    (if (symbolp (setq var (car pat)))
  1125. X        (progn
  1126. X          (push var *destructure-vars*)
  1127. X          (cond ((null (cdr pat))
  1128. X             (push (make-pop var form ()) setqs))
  1129. X            ((symbolp (cdr pat))
  1130. X             (push (make-pop var form (cdr pat)) setqs)
  1131. X             (push (cdr pat) *destructure-vars*)
  1132. X             (return ()))
  1133. X            ((memq var '(nil ignore)) (incf pending-pops))
  1134. X            ((memq (cadr pat) '(nil ignore))
  1135. X             (push (make-pop var form ()) setqs)
  1136. X             (incf pending-pops 1))
  1137. X            (t
  1138. X             (push (make-pop var form form) setqs))))
  1139. X        (progn
  1140. X          (push `(let ((,gensym ()))
  1141. X               ,(make-pop gensym form (if (symbolp (cdr pat)) (cdr pat) form))
  1142. X               ,@(nreverse
  1143. X               (destructure-internal (if (consp pat) (car pat) pat)
  1144. X                         gensym)))
  1145. X            setqs)
  1146. X          (when (symbolp (cdr pat))
  1147. X        (push (cdr pat) *destructure-vars*)
  1148. X        (return)))))
  1149. X      setqs)))
  1150. X
  1151. X;;; Iterate is a simple iteration macro.  If CommonLisp had a standard Loop
  1152. X;;; macro I wouldn't need this wretched crock.  But what the hell, it seems
  1153. X;;; to do most of what I need.  It looks like:
  1154. X;;;   (iterate (<control-clause-1> <control-clause-2> ...)
  1155. X;;;      . <body>)
  1156. X;;;
  1157. X;;;  a control clause can be one of:
  1158. X;;;   (<var> in <list-form>)  | (<var> in <list-form> by <function>)
  1159. X;;;   (<var> on <list-form>)  | (<var> on <list-form> by <function>)
  1160. X;;;   (<var> from <initial> to <final>)
  1161. X;;;   (<var> from <initial> below <final>)
  1162. X;;;   (<var> from <initial> to <final> by <function> | <increment>)
  1163. X;;;   (<var> from <initial> below <final> by <function> | <increment>)
  1164. X;;;   (<var> = <form>)   <form> is evaluated each time through
  1165. X;;;   (<var> = <initial> <subsequent>)
  1166. X;;;   
  1167. X;;;  inside <body> you are allowed to use:
  1168. X;;;    collect
  1169. X;;;    join
  1170. X;;;    sum
  1171. X
  1172. X(defvar *iterate-result-types* ())
  1173. X
  1174. X(defmacro define-iterate-result-type (name arglist &body body)
  1175. X  (let ((fn-name
  1176. X      (if (and (null (cdr body)) (symbolp (car body)))
  1177. X          (car body)
  1178. X          (make-symbol (string-append (symbol-name name) " iterate result type")))))
  1179. X    `(progn
  1180. X       (let ((existing (assq ',name  *iterate-result-types*)))
  1181. X     (if existing
  1182. X         (rplacd existing ',fn-name)
  1183. X         (push ',(cons name fn-name) *iterate-result-types*)))
  1184. X       ,(and (not (and (null (cdr body)) (symbolp (car body))))
  1185. X         `(defun ,fn-name ,arglist . ,body)))))
  1186. X
  1187. X(defmacro iterate (controls &body body)
  1188. X  #+Xerox (setq body (copy-tree body))
  1189. X  (let (binds var-init-steps
  1190. X    pre-end-tests post-end-tests
  1191. X    pre-bodies post-bodies
  1192. X    (result-type ()))
  1193. X    (mapc #'(lambda (control)
  1194. X          (let ((var (car control))
  1195. X            (type (cadr control))
  1196. X            (initial (caddr control))
  1197. X            (args (cdddr control)))
  1198. X        (ecase type
  1199. X          ((in on)
  1200. X           (let* ((gensym (if (or (eq type 'in) (consp var)) (gensym) var))
  1201. X              (step `(,(if args (cadr args) 'cdr) ,gensym)))
  1202. X             (push `(,gensym ,initial ,step) var-init-steps)
  1203. X             (push `(null ,gensym) pre-end-tests)
  1204. X             (cond ((listp var)
  1205. X                (multiple-value-bind (setqs dbinds)
  1206. X                (destructure var (if (eq type 'in) `(car ,gensym) gensym))
  1207. X                  (setq binds (nconc dbinds binds))
  1208. X                  (setq pre-bodies (nconc pre-bodies (nreverse setqs)))))
  1209. X               ((eq type 'in)
  1210. X                (push var binds)
  1211. X                (push `(setq ,var (car ,gensym)) pre-bodies)))))
  1212. X          (from
  1213. X            (let ((gensym (gensym))
  1214. X              (final
  1215. X                (and (memq (car args) '(to below))
  1216. X                 (if (eq (car args) 'to)
  1217. X                     (cadr args)
  1218. X                     `(- ,(cadr args) 1))))
  1219. X              (step
  1220. X                (progn (setq args (member 'by args))
  1221. X                   (cond ((null args)
  1222. X                      `(1+ ,var))
  1223. X                     ((numberp (cadr args))
  1224. X                      `(+ ,var ,(cadr args)))
  1225. X                     (t (cadr args))))))
  1226. X              (push `(,var ,initial ,step) var-init-steps)
  1227. X              (and final (push `(,gensym ,final) binds))
  1228. X              (and final (push `(> , var ,gensym) pre-end-tests))))
  1229. X          (=
  1230. X            (push `(,var ,initial ,(or (car args) initial))
  1231. X              var-init-steps))
  1232. X          )))
  1233. X      controls)
  1234. X    (setq body
  1235. X      (walk-form (cons 'progn body)
  1236. X             :walk-function
  1237. X             #'(lambda (form context &aux aux)
  1238. X             (ignore context)
  1239. X             (or (and (listp form)
  1240. X                  (setq aux (assq (car form) *iterate-result-types*))
  1241. X                  (setq result-type
  1242. X                    (if (null result-type)
  1243. X                        (funcall (cdr aux)
  1244. X                             form nil 'create-result-type)
  1245. X                        (funcall (cdr aux)
  1246. X                             form result-type 'check-result-type)))
  1247. X                  (funcall (cdr aux) form result-type 'macroexpand))
  1248. X                 form))))
  1249. X    (let* ((initially (cons 'progn
  1250. X                (dolist (tlf body)
  1251. X                  (when (and (consp tlf) (eq (car tlf) 'initially))
  1252. X                (return (prog1 (cdr tlf)
  1253. X                           (setf (car tlf) 'progn
  1254. X                             (cdr tlf) ())))))))
  1255. X       (finally (cons 'progn
  1256. X              (dolist (tlf body)
  1257. X                (when (and (consp tlf) (eq (car tlf) 'finally))
  1258. X                  (return (prog1 (cdr tlf)
  1259. X                         (setf (car tlf) 'progn
  1260. X                           (cdr tlf) ()))))))))
  1261. X      `(let (,@binds . ,(caddr result-type))
  1262. X     (iterate-macrolets
  1263. X       (prog ,(mapcar #'(lambda (x) (list (car x) (cadr x)))
  1264. X              var-init-steps)
  1265. X         ,initially
  1266. X          restart
  1267. X         (and (or . ,(reverse pre-end-tests))
  1268. X              (go .iterate_return.))
  1269. X         (progn . ,(reverse pre-bodies))
  1270. X         ,body
  1271. X         (progn . ,(reverse post-bodies))
  1272. X         (or ,@post-end-tests
  1273. X             (progn ,@(mapcar #'(lambda (x)
  1274. X                      (and (cddr x)
  1275. X                           `(setq ,(car x)
  1276. X                              ,(caddr x))))
  1277. X                      var-init-steps)
  1278. X                (go restart)))
  1279. X          .iterate_return.
  1280. X         ,finally
  1281. X         (return ,(cadddr result-type))))))))
  1282. X
  1283. X(define-iterate-result-type collect (form result-type op)
  1284. X  iterate-collect-join)
  1285. X
  1286. X(define-iterate-result-type join (form result-type op)
  1287. X  iterate-collect-join)
  1288. X
  1289. X(defun iterate-collect-join (form result-type op)
  1290. X  (ecase op
  1291. X    (create-result-type
  1292. X      (let ((gensym (gensym)))
  1293. X    `(,(car form) ,gensym ((,gensym ())) (nreverse ,gensym))))
  1294. X    (check-result-type
  1295. X      (if (memq (car result-type) '(collect join))
  1296. X      result-type
  1297. X      (error "Using ~S inside an iterate in which you already used ~S."
  1298. X         (car form) (car result-type))))
  1299. X    (macroexpand
  1300. X      (if (eq (car form) 'collect)
  1301. X      `(push ,(cadr form) ,(cadr result-type))
  1302. X      `(setq ,(cadr result-type)
  1303. X         (append (reverse ,(cadr form)) ,(cadr result-type)))))))
  1304. X
  1305. X(define-iterate-result-type sum (form result-type op)
  1306. X  (ecase op
  1307. X    (create-result-type
  1308. X      (let ((gensym (gensym)))
  1309. X    `(,(car form) ,gensym ((,gensym 0)) ,gensym)))
  1310. X    (check-result-type
  1311. X      (eq (car result-type) 'sum))
  1312. X    (macroexpand
  1313. X      `(incf ,(cadr result-type) ,(cadr form)))))
  1314. X
  1315. X(defmacro iterate-macrolets (&body body)
  1316. X  `(macrolet
  1317. X     ((until (test)
  1318. X        `(when ,test (go .iterate_return.)))
  1319. X      (while (test)
  1320. X    `(until (not ,test)))
  1321. X      (initially (&body body)
  1322. X    (error
  1323. X      "It is an error for FINALLY to appear other than at top-level~%~
  1324. X       inside an iterate."))
  1325. X      (finally (&body ignore)
  1326. X    (error
  1327. X      "It is an error for INITIALLY to appear other than at top-level~%~
  1328. X           inside an iterate."))
  1329. X      )
  1330. X     . ,body))
  1331. X  
  1332. X;;;
  1333. X;;; Two macros useful for parsing defstructs.
  1334. X;;; The first parses slot-description (or lambda-list) style keyword-value
  1335. X;;; pairs.  The second, more complicated one, parses defstruct option style
  1336. X;;; keyword-value pairs.
  1337. X;;;
  1338. X(defmacro keyword-bind (keywords form &body body)
  1339. X  `(apply (function (lambda (&key . ,keywords) . ,body)) ,form))
  1340. X
  1341. X;;;
  1342. X;;;   (keyword-parse (<keyword-spec-1> <keyword-spec-2> ..)
  1343. X;;;                  form
  1344. X;;;      . body)
  1345. X;;;
  1346. X;;; Where form is a form which will be evaluated and should return the list
  1347. X;;; of keywords and values which keyword-parse will parse.  Body will be
  1348. X;;; evaluated with the variables specified by the keyword-specs bound.
  1349. X;;; Keyword specs look like:
  1350. X;;;        <var>
  1351. X;;;        (<var> <default>)
  1352. X;;;        (<var> <default> <suppliedp var>)
  1353. X;;;        (<var> <default> <suppliedp var> <option-1> <val-1> ...)
  1354. X;;;
  1355. X;;;    The options can be:
  1356. X;;;       :allowed     ---  :required   :multiple
  1357. X;;;       :return-cdr  ---  t           nil
  1358. X;;;       
  1359. X(defmacro keyword-parse (keywords form &body body)
  1360. X  ;; This makes an effort to resemble keyword-bind in that the vars are bound
  1361. X  ;; one at a time so that a default value form can look at the value of a
  1362. X  ;; previous argument. This is probably more hair than its worth, but what
  1363. X  ;; the hell, programming is fun.
  1364. X  (let* ((lambda-list ())
  1365. X         (supplied-p-gensyms ())
  1366. X         (value-forms ())
  1367. X         (entry-var (gensym)))
  1368. X    (dolist (kw keywords)
  1369. X      (unless (listp kw) (setq kw (list kw)))      
  1370. X      (destructuring-bind (var default supplied-p-var . options) kw
  1371. X        (keyword-bind (presence (allowed ':required) return-cdr) options
  1372. X          (push var lambda-list)
  1373. X          (when supplied-p-var
  1374. X            (push supplied-p-var lambda-list)
  1375. X            (push (gensym) supplied-p-gensyms))
  1376. X          (push `(let ((,entry-var (keyword-parse-assq ',(make-keyword var)
  1377. X                               ,form
  1378. X                               ',allowed)))
  1379. X                   (if (null ,entry-var)
  1380. X                       ,default
  1381. X                       ;; Insert appropriate error-checking based on the
  1382. X                       ;; allowed argument.
  1383. X                       (progn
  1384. X                       ,(when (null allowed)
  1385. X                          `(unless (nlistp (car ,entry-var))
  1386. X                             (error "The ~S keyword was supplied with an ~
  1387. X                                    argument, it is not allowed to have one."
  1388. X                                    ',(make-keyword var))))
  1389. X                       ,(when (eq allowed ':required)
  1390. X                          `(unless (listp (car ,entry-var))
  1391. X                             (error
  1392. X                   "The ~S keyword was supplied without an ~
  1393. X                                argument~%when present, this keyword must ~
  1394. X                                have an argument."
  1395. X                               ',(make-keyword var))))
  1396. X                       (cond ((listp (car ,entry-var))
  1397. X                              ,(and supplied-p-var
  1398. X                                    `(setq ,(car supplied-p-gensyms) 't))
  1399. X                              ,(if return-cdr
  1400. X                   (if (eq allowed ':multiple)
  1401. X                       `(mapcar #'cdr ,entry-var)
  1402. X                       `(cdar ,entry-var))
  1403. X                   (if (eq allowed ':multiple)
  1404. X                       `(mapcar #'cadr ,entry-var)
  1405. X                       `(cadar ,entry-var))))
  1406. X                             (t
  1407. X                              ,(and supplied-p-var
  1408. X                                    `(setq ,(car supplied-p-gensyms)
  1409. X                       ':presence))
  1410. X                              ,presence)))))
  1411. X                value-forms)
  1412. X          (when supplied-p-var
  1413. X            (push (car supplied-p-gensyms) value-forms)))))
  1414. X    `(let ,supplied-p-gensyms
  1415. X       ((lambda ,(reverse lambda-list) . ,body) . ,(reverse value-forms)))))
  1416. X
  1417. X
  1418. X(defun keyword-parse-assq (symbol list allowed)
  1419. X  (do ((result nil result)
  1420. X       (tail list (cdr tail)))
  1421. X      ((null tail) (nreverse result))
  1422. X    (if (eq (if (symbolp (car tail)) (car tail) (caar tail)) symbol)
  1423. X    (if (neq allowed ':multiple)
  1424. X        (return tail)
  1425. X        (push (car tail) result)))))
  1426. X
  1427. X  ;;   
  1428. X;;;;;; printing-random-thing
  1429. X  ;;
  1430. X;;; Similar to printing-random-object in the lisp machine but much simpler
  1431. X;;; and machine independent.
  1432. X(defmacro printing-random-thing ((thing stream) &body body)
  1433. X  (once-only (stream)
  1434. X  `(let ((*print-level* (and (numberp *print-level*) (- *print-level* 1))))
  1435. X     (progn (princ "#<" ,stream)
  1436. X            ,@body
  1437. X        (princ " " ,stream)
  1438. X        (printing-random-thing-internal ,thing ,stream)
  1439. X        (princ ">" ,stream)))))
  1440. X
  1441. X(defun printing-random-thing-internal (thing stream)
  1442. X  (ignore thing stream)
  1443. X  nil)
  1444. X
  1445. X  ;;   
  1446. X;;;;;; 
  1447. X  ;;
  1448. X
  1449. X(defun capitalize-words (string)
  1450. X  (let ((string (copy-seq (string string))))
  1451. X    (declare (string string))
  1452. X    (do* ((flag t flag)
  1453. X      (length (length string) length)
  1454. X      (char nil char)
  1455. X      (i 0 (+ i 1)))
  1456. X     ((= i length) string)
  1457. X      (setq char (elt string i))
  1458. X      (cond ((both-case-p char)
  1459. X         (if flag
  1460. X         (and (setq flag (lower-case-p char))
  1461. X              (setf (elt string i) (char-upcase char)))
  1462. X         (and (not flag) (setf (elt string i) (char-downcase char))))
  1463. X         (setq flag nil))
  1464. X        ((char-equal char #\-)
  1465. X         (setq flag t))
  1466. X        (t (setq flag nil))))))
  1467. X
  1468. X  ;;
  1469. X;;;;;; CLASS-NAMED  naming classes.
  1470. X  ;;
  1471. X;;;
  1472. X;;; (CLASS-NAMED <name>) returns the class named <name>.  setf can be used
  1473. X;;; with class-named to set the class named <name>.  These are "extrinsic"
  1474. X;;; names.  Neither class-named nor setf of class-named do anything with the
  1475. X;;; name slot of the class, they only lookup and change the association from
  1476. X;;; name to class.
  1477. X;;; 
  1478. X
  1479. X(defvar *class-name-hash-table* (make-hash-table :test #'eq))
  1480. X
  1481. X(defun class-named (name &optional no-error-p)
  1482. X  (or (gethash name *class-name-hash-table*)
  1483. X      (if no-error-p () (error "No class named: ~S." name))))
  1484. X
  1485. X(defsetf class-named (name &optional ignore-damnit) (class)
  1486. X  `(setf (gethash ,name *class-name-hash-table*) ,class))
  1487. X
  1488. X
  1489. X(defvar *discriminator-name-hash-table* (make-hash-table :test #'eq
  1490. X                             :size 1000))
  1491. X
  1492. X(defun discriminator-named (name)                ;This a function for
  1493. X  (gethash name *discriminator-name-hash-table*))    ;the benefit of
  1494. X                                ;compile-time-define?
  1495. X
  1496. X(defun set-discriminator-named (name new-value)
  1497. X  (setf (gethash name *discriminator-name-hash-table*) new-value))
  1498. X
  1499. X(defsetf discriminator-named set-discriminator-named)
  1500. X
  1501. X;;;
  1502. X;;; To define a macro which is only applicable in the body of a defmethod,
  1503. X;;; use define-method-body-macro.  This macro takes two arguments the name
  1504. X;;; of the macro that should be defined in the body of the method and the
  1505. X;;; function which should be called to expand calls to that macro.
  1506. X;;; 
  1507. X;;; Expander-function will be called with 3 arguments:
  1508. X;;; 
  1509. X;;;   the entire macro form (gotten with &whole)
  1510. X;;;   the macroexpand-time-information
  1511. X;;;   the environment
  1512. X;;;   
  1513. X
  1514. X(defvar *method-body-macros* ())
  1515. X
  1516. X(defmacro define-method-body-macro (name arglist &key global method)
  1517. X  (when (eq global :error)
  1518. X    (setq global
  1519. X      `(progn (warn "~S used outside the body of a method." ',name)
  1520. X          '(error "~S used outside the body of a method." ',name))))
  1521. X  (or method
  1522. X      (error "Have to provide a value for the method-body definition of~%~
  1523. X              a macro defined with define-method-body-macro."))
  1524. X  #+KCL (when (memq '&environment arglist)
  1525. X      ;; In KCL, move &environment to the beginning of the
  1526. X      ;; arglist since they require that it be there.
  1527. X      (unless (eq (car arglist) '&environment)
  1528. X        (do ((loc arglist (cdr loc)))
  1529. X        ((eq (cadr loc) '&environment)
  1530. X         (setq arglist (list* (cadr loc) (caddr loc) arglist))
  1531. X         (setf (cdr loc) (cdddr loc))))))
  1532. X  (let ((body-expander-function (gensym))
  1533. X    (parameters (remove lambda-list-keywords arglist
  1534. X                :test #'(lambda (x y) (member y x)))))
  1535. X    `(eval-when (compile load eval)
  1536. X       ,(and global `(defmacro ,name ,arglist ,global))
  1537. X       (defun ,body-expander-function
  1538. X          (macroexpand-time-environment ,@parameters)
  1539. X     ,method)
  1540. X     
  1541. X       (let ((entry (or (assq ',name *method-body-macros*)
  1542. X            (progn (push (list ',name) *method-body-macros*)
  1543. X                   (car *method-body-macros*)))))
  1544. X     (setf (cdr entry) (list ',arglist
  1545. X                 ',parameters
  1546. X                 ',body-expander-function))))))
  1547. X
  1548. X  ;;   
  1549. X;;;;;; Special variable definitions.
  1550. X  ;;
  1551. X;;; Gets set to its right value once early-defmeths are fixed.
  1552. X;;; 
  1553. X(defvar *error-when-defining-method-on-existing-function* 'bootstrapping
  1554. X  "If this variable is non-null (the default) defmethod signals an error when
  1555. X   a method is defined on an existing lisp-function without first calling
  1556. X   make-specializable on that function.")
  1557. X
  1558. END_OF_FILE
  1559. if test 25561 -ne `wc -c <'macros.l'`; then
  1560.     echo shar: \"'macros.l'\" unpacked with wrong size!
  1561. fi
  1562. # end of 'macros.l'
  1563. fi
  1564. echo shar: End of archive 7 \(of 13\).
  1565. cp /dev/null ark7isdone
  1566. MISSING=""
  1567. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  1568.     if test ! -f ark${I}isdone ; then
  1569.     MISSING="${MISSING} ${I}"
  1570.     fi
  1571. done
  1572. if test "${MISSING}" = "" ; then
  1573.     echo You have unpacked all 13 archives.
  1574.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1575. else
  1576.     echo You still need to unpack the following archives:
  1577.     echo "        " ${MISSING}
  1578. fi
  1579. ##  End of shell archive.
  1580. exit 0
  1581. -- 
  1582.  
  1583. Rich $alz            "Anger is an energy"
  1584. Cronus Project, BBN Labs    rsalz@bbn.com
  1585. Moderator, comp.sources.unix    sources@uunet.uu.net
  1586.